package gcp.principal;

import gcp.Amigo;
import gcp.Colecionavel;
import gcp.Emprestimo;
import gcp.Usuario;
import gcp.cadastros.CadastroAmigo;
import gcp.cadastros.CadastroEmprestimo;
import gcp.cadastros.CadastroUsuario;
import gcp.cadastros.Cadastros;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.util.List;

/**
 * GCP<br>
 * Modulo GCP que sera resposavel pelo fucionamento de um gerenciador pessoal de
 * colecoes, este mantera todas as entidades envolvidas pelo gerenciador.
 * @author Hildegard Furtado
 */
public class GCP implements Serializable {
    private static final long serialVersionUID = 1L;

    private Cadastros cadastros;
    private CadastroUsuario cadastroUsuario;
    private CadastroAmigo cadastroAmigo;
    private CadastroEmprestimo cadastroEmprestimo;

    /**
     * Construtor default para GCP
     */
    public GCP() {
        cadastroUsuario = new CadastroUsuario();
        cadastroAmigo = new CadastroAmigo();
        cadastros = new Cadastros();
        cadastroEmprestimo = new CadastroEmprestimo();
    }

    /**
     * Carrega o GCP do arquivo XML e retorna.
     * @return GCP.
     */
    public static GCP carregarGCP() {
        try {
            XMLDecoder decoder = new XMLDecoder(new FileInputStream("GCP.xml"));
            GCP gcp = (GCP) decoder.readObject();
            decoder.close();
            return gcp;
        } catch (FileNotFoundException ex) {
            return new GCP();
        }
    }

    /**
     * Grava o GCP em XML.
     */
    public void gravar() {
        try {
            XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
                    new FileOutputStream("GCP.xml")));
            encoder.writeObject(this);
            encoder.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("Nao foi possivel gravar.");
        }
    }

    /**
     * Adiciona um Usuario ao GCP.
     * @param usuario Usuario a ser adicionado.
     * @throws Exception lanca em caso de algum parametro do Usuario ser nulo.
     */
    public void adicionaUsuario(Usuario usuario) throws Exception {
        cadastroUsuario.addUsuario(usuario);
    }

    /**
     * Remove o Usuario do GCP e todas as suas colecoes.
     * @param usuario Usuario do GCP.
     * @throws Exception lanca excecao caso o login do Usuario seja nulo.
     */
    public void removeUsuario(Usuario usuario) throws Exception {
        cadastroUsuario.removerUsuario(usuario.getLogin());
        cadastroAmigo.removerUsuario(usuario);
        cadastros.removerUsuario(usuario);
    }

    /**
     * Adiciona um item que foi pego emprestado.
     * @param emprestimo Emprestimo a ser adicionado.
     * @throws Exception Lancada quando o item for nulo.
     */
    public void adicionaEmprestimo(Emprestimo emprestimo) throws Exception {
        cadastroEmprestimo.adicionaEmprestimo(emprestimo);
    }

    /**
     * Remove um item que havia sido pego emprestado e que sera devolvido.
     * @param item Item que vai ser devolvido.
     * @throws Exception Lancada quando o item for nulo ou nao estiver
     *             cadastrado no sistema.
     */
    public void removeEmprestimo(Emprestimo item) throws Exception {
        cadastroEmprestimo.removeEmprestimo(item);
    }

    /**
     * Adiciona um Colecionavel a aista de colecionaveis do Usuario.
     * @param colecionavel O Colecionavel a ser adicionado.
     * @throws Exception Lancada quando o item for nulo.
     */
    public void adicionaItens(Usuario usuario, Colecionavel colecionavel)
            throws Exception {
        if (cadastroUsuario.get(usuario.getLogin()) != null) {
            cadastros.adiciona(usuario, colecionavel);
        } else {
            throw new Exception("Usuario" + usuario.getLogin()
                    + "nao possui conta nesse gerenciador, portanto, "
                    + "nao pode adicionar um Colecionavel!");
        }
    }

    /**
     * Adiciona um Amigo ao GCP do Usuario.
     * @param usuario do GCP.
     * @param amigo Amigo a ser adicionado ao GCP do Usuario.
     * @throws Exception lanca caso login do Usuario for nulo.
     */
    public void adicionaAmigo(Usuario usuario, Amigo amigo) throws Exception {
        if (cadastroUsuario.get(usuario.getLogin()) != null) {
            cadastroAmigo.adicionaAmigo(usuario, amigo);
        } else {
            throw new Exception(
                    "Usuario"
                            + usuario.getLogin()
                            + "nao possui conta nesse gerenciador, logo, nao eh possivel adicionar um novo amigo!");
        }
    }

    /**
     * Remove um Amigo do GCP do Usuario.
     * @param usuario do GCP.
     * @param amigo Amigo a ser removido do GCP do Usuario.
     * @throws Exception lanca caso login do Usuario for nulo.
     */
    public void removeAmigo(Usuario usuario, Amigo amigo) throws Exception {
        if (cadastroUsuario.get(usuario.getLogin()) != null) {
            cadastroAmigo.removeAmigo(usuario, amigo);
        } else {
            throw new Exception(
                    "Usuario"
                            + usuario.getLogin()
                            + "nao possui conta nesse gerenciador, logo, nao eh possivel remover o amigo!");
        }
    }

    /**
     * Remove um determinado Colecionavel da lista e colecionaveis do Usuario
     * @param usuario Usuario do GCP
     * @param colecionavel O Colecionavel a ser removido
     * @throws Exception lancada quando o Usuario nao possui conta no GCP
     */
    public void remover(Usuario usuario, Colecionavel colecionavel)
            throws Exception {
        if (cadastroUsuario.get(usuario.getLogin()) != null) {
            cadastros.removeColecionavel(usuario, colecionavel);
        } else {
            throw new Exception("Usuario" + usuario.getLogin()
                    + "nao possui conta nesse gerenciador de colecoes "
                    + "pessoais, portanto nao possui filmes a "
                    + "serem removidos");
        }
    }

    /**
     * Remove um determinado Usuartio da lista de Usuario
     * @param usuario - O Usuario jah cadastrado no GCP a ser removido
     * @throws Exception
     * @throws Exception lancada quando o Usuario nao possui conta no GCP
     */
    public void removerUsuario(Usuario usuario) throws Exception {
        cadastroAmigo.removerUsuario(usuario);
        cadastros.removerUsuario(usuario);
        cadastroEmprestimo.removerUsuario(usuario);
        cadastroUsuario.removerUsuario(usuario.getLogin());
    }

    /**
     * Retorna um Usuario do GCP atarves de seu login.
     * @param login login do Usuario do GCP.
     * @return usuario Usuario do GCP.
     */
    public Usuario getUsuario(String login) {
        return cadastroUsuario.get(login);
    }

    /**
     * Retorna o amigo do usuario.
     * @param usuario Usuario do GCP.
     * @param nome Nome do Amigo do Usuario do GCP.
     * @param sobrenome Sobrenome do Amigo do Usuario do GCP.
     * @return amigo Amigo do Usuario do GCP.
     * @throws Exception lanca caso o usuario seja nulo ou amigo seja nulo.
     */
    public Amigo getAmigo(Usuario usuario, String nome, String sobrenome)
            throws Exception {
        return cadastroAmigo.getAmigo(usuario, nome, sobrenome);
    }

    /**
     * Retorna o item do usuario que contenha o titulo indicado.
     * @param usuario Usuario.
     * @param titulo Título do item.
     * @return Item colecionavel com titulo indicado.
     */
    public Colecionavel get(Usuario usuario, String titulo) {
        return cadastros.get(usuario, titulo);
    }

    /**
     * Retorna a lista de itens colecionaveis do usuario.
     * @param usuario Usuario.
     * @return Lista de itens colecionaveis.
     */
    public List<Colecionavel> getList(Usuario usuario) {
        return cadastros.getList(usuario);
    }

    /**
     * Retorna uma lista de todos os Usuarios.
     * @return lista de de todos os Usuarios.
     */
    public List<Usuario> getListUsuario() {
        return cadastroUsuario.getUsuarios();
    }

    /**
     * Retorna uma lista de Amigos do Usuario indicado
     * @param usuario Usuario
     * @return lista de Amigos de um dado Usuario
     */
    public List<Amigo> getListAmigo(Usuario usuario) {
        return cadastroAmigo.getList(usuario);
    }

    /**
     * Retorna a cadastroUsuario do GCP
     * @return cadastroUsuario CadastroUsuario
     */
    public CadastroUsuario getCadastroUsuario() {
        return cadastroUsuario;
    }

    /**
     * Define a CadastroUsuario
     * @param cadastroUsuario CadastroUsuario
     */
    public void setCadastroUsuario(CadastroUsuario cadastroUsuario) {
        this.cadastroUsuario = cadastroUsuario;
    }

    /**
     * Retorna a cadastroAmigo do GCP
     * @return cadastroAmigo CadastroAmigo
     */
    public CadastroAmigo getCadastroAmigo() {
        return cadastroAmigo;
    }

    /**
     * Define a CadastroAmigo
     * @param cadastroAmigo CadastroAmigo
     */
    public void setCadastroAmigo(CadastroAmigo cadastroAmigo) {
        this.cadastroAmigo = cadastroAmigo;
    }

    /**
     * Retorna o CadastroEmprestimo do GCP.
     * @return cadastroEmprestimo CadastroEmprestimo.
     */
    public CadastroEmprestimo getCadastroEmprestimo() {
        return cadastroEmprestimo;
    }

    /**
     * Retorna uma lista de Emprestimos do Usuario indicado
     * @param usuario Usuario
     * @return Lista de emprestimos do usuario.
     */
    public List<Emprestimo> getListEmprestimos(Usuario usuario) {
        return cadastroEmprestimo.getItensEmprestados(usuario);
    }

    /**
     * Retorna os Cadastros dos Colecionaveis
     * @return cadastros Os cadastros dos Colecionaveis
     */
    public Cadastros getCadastros() {
        return cadastros;
    }

    /**
     * Altera/Define os Cadastros dos Colecionaveis
     * @param cadastros Os cadastros dos Colecionaveis
     */
    public void setCadastros(Cadastros cadastros) {
        this.cadastros = cadastros;
    }

    /**
     * Define o cadastro de emprestimos.
     * @param cadastroEmprestimo Cadastro de emprestimos.
     */
    public void setCadastroEmprestimo(CadastroEmprestimo cadastroEmprestimo) {
        this.cadastroEmprestimo = cadastroEmprestimo;
    }

    /**
     * Retorna os emprestimos que foram pegos de amigos.
     * @param usuario Usuario.
     * @return Lista de emprestimos.
     */
    public List<Emprestimo> getListEmprestimosDeAmigos(Usuario usuario) {
        return cadastroEmprestimo.getItensPedidosEmprestados(usuario);
    }
}